home *** CD-ROM | disk | FTP | other *** search
- /* disp.c */
-
- /* JOVE/MSDOS. K. Mitchum 1/85 */
- /* Modifications for personal use only. */
- /* original code J. Payne LSRHS 5/83 */
- /* Ken Mitchum */
- /* University of Pittsburgh */
- /* Decision Systems Laboratory */
-
-
- /* Jonathan Payne at Lincoln-Sudbury Regional High School 5-25-83
-
- jove_disp.c
-
- This code figures out the best way to update the screen.
- It contains the procedure "redisplay()" that should be called
- whenever the screen needs updating. This optimizes interline
- movement and intraline movement, taking advantage of insert/delete
- line/character features of the terminal (if they exist). */
-
- #include "jove.h"
- #include "term.h"
- #include "screen.h"
-
- #ifdef UNIX
- #include <signal.h>
- #else
- #include "signal.h"
- #endif
-
- #define TOPGONE 01
- #define CURGONE 02 /* Topline (curline) of window has been deleted
- since the last time a redisplay was called. */
-
- extern int errormsg; /* main.c */
- extern int ScrollStep;
- extern char mesgbuf[];
- extern char *cursend;
- extern SCRLNE *Screen;
- extern SCRLNE *Curline;
-
-
- int UpdModLine = 0;
-
-
- int UpdWCalls, /* Number of times we called UpdateWindow for this window */
- IDstart, /* First different line */
- NumDirty; /* Number of dirty lines in this screen update */
-
-
- static struct scrimage dirty_plate = { 0, DIRTY, 0, 0 };
- static struct scrimage clean_plate = { 0, 0, 0, 0 };
-
- /* Kludge windows gets called by the routines that delete lines from the
- buffer. If the w->w_line or w->w_top are deleted and this procedure
- is not called, the redisplay routine will barf. */
-
- KludgeWindows(line1, line2)
- LINE *line1;
- register LINE *line2;
- {
- register WINDOW *w = fwind;
- register LINE *lp;
-
- do {
- for (lp = line1->l_next; lp != line2->l_next; lp = lp->l_next) {
- if (lp == w->w_top)
- w->w_flags |= TOPGONE;
- if (lp == w->w_line)
- w->w_flags |= CURGONE;
- }
- w = w->w_next;
- } while (w != fwind);
- }
-
- inlist(first, what)
- register LINE *first,
- *what;
- {
- while (first) {
- if (first == what)
- return 1;
- first = first->l_next;
- }
- return 0;
- }
-
-
-
-
- /* The redisplay algorithm:
-
- Jove remembers where each buffer lines is on the screen in the array
- `oimage' (old image). UpdateWindow() makes a new image, in `nimage',
- by started from w->w_top and working to the bottom line of the window.
- A line by line comparison starts from nimage[0] and oimage[0], and if
- there are no differences, no insert/delete lines is done. When there
- is a difference, there are two possibilities:
-
- Some lines were deleted in the buffer. This is detected by looking
- further down in the old image, for the line where the difference occurred
- in the new image. So where we used to have 1-2-3-4 (oimage), we now have
- 1-4, in which case two lines were deleted.
-
- Some lines were inserted in the buffer. This is detected by looking
- further down in the new image, for the line where the difference occurred
- in the old image. So where we used to have 1-2-3, we now have 1-2-4-5-3,
- in which case two lines were inserted (lines 4 and 5).
-
- UpdateWindow has a few optimizations in it, e.g. it checks for
- mismatches AS it builds `nimage', and sets a variable to the line number
- at which the difference occurred. It also keeps a count of the number
- of lines that need updating i.e. the line was changed by an editing
- operation, or the start print column is different (the line just scrolled
- left or right). Imagine that a single character was inserted on the top
- line of the screen. The number of lines that are dirty = 1, so the loop
- that checks to see that all the lines are up-to-date can terminate after
- updating the first line WITHOUT checking the rest of the lines. */
-
- redisplay()
- {
- register WINDOW *w = fwind;
- int lineno,
- i;
- register struct scrimage *np,
- *op;
-
- curwind->w_bufp = curbuf;
- if (curwind->w_line != curline)
- curwind->w_offset = 0;
- curwind->w_line = curline;
- curwind->w_char = curchar;
-
- if (InputPending = charp())
- return;
- if (RingBell) sendbell();
-
- /* So messages that aren't error messages don't hang around forever */
- if (!UpdMesg && !Asking) { /* Don't erase if we are asking */
- if (mesgbuf[0] && !errormsg)
- message("");
- }
- if (UpdMesg)
- UpdateMesg();
-
- NumDirty = 0;
- IDstart = -1;
-
- for (lineno = 0, w = fwind; lineno < LI - 1; w = w->w_next) {
- UpdWCalls = 0;
- UpdateWindow(w, lineno);
- lineno += w->w_height;
- }
-
- if (IDstart != -1) { /* Shucks this is gonna be slower */
- DoIDline(IDstart);
- NumDirty = LI - 1;
- }
-
- np = nimage;
- op = oimage;
- for (i = 0; i < LI - 1 && NumDirty > 0; i++, np++, op++) {
- if ((np->Sflags & DIRTY) ||
- op->Line != np->Line ||
- op->StartCol != np->StartCol ||
- (UpdModLine && np->Sflags & MODELINE)) {
- UpdateLine(np->Window, i);
- NumDirty--;
- }
- if (InputPending)
- return;
- }
- UpdModLine = 0;
-
- if (InputPending)
- return;
- if (Asking) {
- Placur(LI - 1, calc_pos(mesgbuf, Asking));
- /* Nice kludge */
- flusho();
- } else
- GotoDot();
- }
-
-
- DoIDline(start)
- {
- register struct scrimage *np = nimage,
- *op = oimage;
- register int i;
- int j;
-
- /* Some changes have been made. Try for insert or delete lines.
- If either case has happened, Addlines and/or DeltLines will do
- necessary scrolling, also CONVERTING oimage to account for the
- physical changes. The comparison continues from where the
- insertion/deletion takes place; this doesn't happen very often,
- usually it happens with more than one window with the same
- buffer. */
-
- if (!CanScroll)
- return; /* We should never have been called! */
-
- for (i = start; i < LI - 1; i++) {
- for (j = i + 1; j < LI - 1; j++) {
- if (np[j].Line != 0 && np[j].Line == op[j].Line)
- break;
- if (np[j].Line == op[i].Line) {
- if (np[j].Line == 0)
- continue;
- if (AddLines(i, j - i)) {
- DoIDline(j);
- return;
- }
- break;
- }
- if (np[i].Line == op[j].Line) {
- if (np[i].Line == 0)
- continue;
- if (DeltLines(i, j - i)) {
- DoIDline(i);
- return;
- }
- break;
- }
- }
- }
- }
-
- /* Make nimage reflect what the screen should look like when we are done
- with the redisplay. This deals with horizontal scrolling. Also makes
- sure the current line of the window is in the window. */
-
- UpdateWindow(w, start)
- register WINDOW *w;
- {
- LINE *lp;
- int i,
- DotIsHere = 0,
- upper, /* Top of window */
- lower; /* Bottom of window */
- register struct scrimage *np,
- *op;
- int savestart = IDstart;
-
- if (w->w_flags & CURGONE) {
- w->w_line = w->w_bufp->b_dot;
- w->w_char = w->w_bufp->b_char;
- }
- if (w->w_flags & TOPGONE)
- CalcTop(w); /* Reset topline of screen */
- w->w_flags = 0;
-
- upper = start;
- lower = upper + w->w_height - 1; /* Don't include modeline */
- np = &nimage[upper];
- op = &oimage[upper];
- for (i = upper, lp = w->w_top; lp != 0 && i < lower;
- i++, np++, op++, lp = lp->l_next) {
- if (lp == w->w_line) {
- w->w_dotcol = find_pos(lp, w->w_char);
- w->w_dotline = i;
-
- if (w->w_numlines)
- w->w_dotcol += 8;
- DotIsHere++;
- if (w->w_dotcol < np->StartCol ||
- (w->w_dotcol + 2) >= (np->StartCol + CO)) {
- if (w->w_dotcol + 2 < CO)
- w->w_offset = 0;
- else
- w->w_offset = w->w_dotcol - (CO / 2);
- }
- np->StartCol = w->w_offset;
- } else
- np->StartCol = 0;
-
- if ((np->Sflags = (lp->l_dline & DIRTY)) ||
- np->StartCol != op->StartCol)
- NumDirty++;
- if (((np->Line = lp) != op->Line) && IDstart == -1)
- IDstart = i;
- np->Window = w;
- }
- if (!DotIsHere) { /* Current line not in window */
- if (UpdWCalls != 0) {
- printf("\rCalled UpdateWindow too many times");
- finish(SIGHUP);
- }
- IDstart = savestart;
- UpdWCalls++;
- CalcScroll(w);
- UpdateWindow(w, start); /* This time for sure */
- return;
- }
-
- /* Is structure assignment faster than copy each field seperately */
- if (i < lower) {
-
- for (; i < lower; i++, np++, op++) {
- if (np->Sflags = ((op->Line) ? DIRTY : 0)) {
- NumDirty++;
- #ifdef UNIX
- *np = dirty_plate;
- #else
- /* np->StartCol = dirty_plate.StartCol;
- np->Sflags = dirty_plate.Sflags;
- np->Line = dirty_plate.Line;
- np->Window = dirty_plate.Window;
- */
- movmem(&dirty_plate,np,sizeof(struct scrimage));
- #endif
- } else
- #ifdef UNIX
- *np = clean_plate;
- #else
- /* np->StartCol = clean_plate.StartCol;
- np->Sflags = clean_plate.Sflags;
- np->Line = clean_plate.Line;
- np->Window = clean_plate.Window;
- */
- movmem(&clean_plate,np,sizeof(struct scrimage));
- #endif
- }
- }
-
- if (((np->Line = (LINE *) w->w_bufp) != op->Line) || UpdModLine) {
- if (IDstart == -1)
- IDstart = i;
- NumDirty++;
- }
-
- np->Sflags = MODELINE;
- np->Window = w;
- }
-
- /* Make `buf' modified and tell the redisplay code to update the modeline
- if it will need to be changed. */
-
- SetModified(buf)
- BUFFER *buf;
- {
- extern int DOLsave;
-
- if (!buf->b_modified)
- UpdModLine++;
- buf->b_modified = 1;
- DOLsave++;
- }
-
- SetUnmodified(buf)
- BUFFER *buf;
- {
- if (buf->b_modified)
- UpdModLine++;
- buf->b_modified = 0;
- }
-
- /* Write whatever is in mesgbuf (maybe we are Asking, or just printed
- a message. Turns off the Update Mesg line flag */
-
- UpdateMesg()
- {
- i_set(LI - 1, 0);
- if (swrite(mesgbuf,0)) {
- cl_eol();
- UpdMesg = 0;
- }
- flusho();
- }
-
- /* Goto the current position in the current window. Presumably redisplay()
- has already been called, and curwind->{w_dotline,w_dotcol} have been set
- correctly. */
-
- GotoDot()
- {
- if (InputPending)
- return;
- Placur(curwind->w_dotline, curwind->w_dotcol -
- oimage[curwind->w_dotline].StartCol);
- flusho();
- }
-
- /* Put the current line of `w' in the middle of the window */
-
- CalcTop(w)
- WINDOW *w;
- {
- SetTop(w, prev_line(w->w_line, HALF(w)));
- }
-
-
-
- /* Calculate the new topline of the screen; different when in single-scroll
- mode */
-
- CalcScroll(w)
- register WINDOW *w;
- {
- extern int diffnum;
- register int up;
-
- if (ScrollStep == 0) /* Means just center it */
- CalcTop(w);
- else {
- up = inorder(w->w_line, 0, w->w_top, 0);
- if (up) /* Dot is above the screen */
- SetTop(w, prev_line(w->w_line, min(ScrollStep - 1, HALF(w))));
- else
- SetTop(w, prev_line(w->w_line,
- (SIZE(w) - 1) -
- min(ScrollStep - 1, HALF(w))));
- }
- }
-
- UntilEqual(start)
- register int start;
- {
- register struct scrimage *np = &nimage[start],
- *op = &oimage[start];
-
- while ((start < LI - 1) && (np->Line != op->Line)) {
- np++;
- op++;
- start++;
- }
-
- return start;
- }
-
- /* Calls the routine to do the physical changes, and changes oimage to
- reflect those changes. */
-
- AddLines(at, num)
- register int at,
- num;
- {
- register int i;
- int bottom = UntilEqual(at + num);
-
- if (num == 0 || num >= ((bottom - 1) - at))
- return 0; /* We did nothing */
- v_ins_line(num, at, bottom - 1);
-
- /* Now change oimage to account for the physical change */
- #ifdef UNIX
- for (i = bottom - 1; i - num >= at; i--) { /***/
-
- oimage[i] = oimage[i - num];
-
- /* oimage[i].StartCol = oimage[i-num].StartCol;
- oimage[i].Sflags = oimage[i-num].Sflags;
- oimage[i].Line = oimage[i-num].Line;
- oimage[i].Window = oimage[i-num].Window;
- */
- /* movmem(oimage+i-num,oimage+i,sizeof(struct scrimage)); */
- }
- #else
- i = bottom -at -num;
- movmem(oimage+at,oimage+at+num, i * sizeof(struct scrimage));
- #endif
-
- for (i = 0; i < num; i++)
- oimage[at + i].Line = 0;
- return 1; /* We did something */
- }
-
- DeltLines(at, num)
- register int at,
- num;
- {
- register int i;
- int bottom = UntilEqual(at + num);
-
- if (num == 0 || num >= ((bottom - 1) - at))
- return 0;
- v_del_line(num, at, bottom - 1);
-
- #ifdef UNIX
- for (i = at; num + i < bottom; i++) {
-
- oimage[i] = oimage[num + i]; /****/
-
- /* oimage[i].StartCol = oimage[i+num].StartCol;
- oimage[i].Sflags = oimage[i+num].Sflags;
- oimage[i].Line = oimage[i+num].Line;
- oimage[i].Window = oimage[i+num].Window;
- */
- /* movmem(oimage+i+num,oimage+i,sizeof(struct scrimage)); */
-
- }
- #else
- i = bottom - at - num;
- movmem(oimage+at+num,oimage+at, i * sizeof(struct scrimage));
- #endif
-
- for (i = bottom - num; i < bottom; i++)
- oimage[i].Line = 0;
- return 1;
- }
-
- DeTab(StartCol, buf, outbuf, limit)
- register char *buf;
- char *outbuf;
- {
- register char *op = outbuf,
- c;
- register int pos = 0;
-
- #define OkayOut(ch) if ((pos++ >= StartCol) && (op < &outbuf[limit]))\
- *op++ = ch;\
- else
-
- while (c = *buf++) {
- if (c == '\t') {
- int nchars = (tabstop - (pos % tabstop));
-
- while (nchars--)
- OkayOut(' ');
-
- } else if (c < ' ' || c == 0177) {
- OkayOut('^');
- OkayOut(c == 0177 ? '?' : c + '@');
- } else
- OkayOut(c);
- if (pos - StartCol >= CO) {
- op = &outbuf[CO - 1];
- *op++ = '!';
- break;
- }
- }
- *op = 0;
- }
-
- /* Update line linenum in window w. Only set oimage to nimage if
- * the swrite or cl_eol works, that is nothing is interupted by
- * characters typed
- */
-
- UpdateLine(w, linenum)
- register WINDOW *w;
- register int linenum;
- {
-
- register struct scrimage *np = &nimage[linenum];
-
- if (np->Sflags == MODELINE)
- ModeLine(w);
- else if (np->Line) {
- np->Line->l_dline &= ~DIRTY;
- np->Sflags &= ~DIRTY;
- i_set(linenum, 0);
- if (!hasIC && w->w_numlines)
- ignore(swrite(sprint("%6d ", (linenum - FLine(w) +
- w->w_topnum)),0));
- if (hasIC) {
- char outbuf[132],
- buff[LBSIZE],
- *bptr;
- int fromcol = w->w_numlines ? 8 : 0;
-
- if (w->w_numlines) {
- ignore(sprintf(buff, "%6d ", (linenum - FLine(w) +
- w->w_topnum)));
- ignore(getcptr(np->Line, buff + fromcol));
- bptr = buff;
- } else
- bptr = getcptr(np->Line, buff);
- DeTab(np->StartCol, bptr,
- outbuf, (sizeof outbuf) - 1);
- if (!IDchar(outbuf, linenum, 0)) {
- #ifdef UNIX
- oimage[linenum] = *np; /***/
- #else
- /* oimage[linenum].StartCol = np->StartCol;
- oimage[linenum].Sflags = np->Sflags;
- oimage[linenum].Line = np->Line;
- oimage[linenum].Window = np->Window;
- */
- movmem(np,oimage+linenum,sizeof(struct scrimage));
- #endif
- } else if (i_set(linenum, 0), swrite(outbuf,0))
- do_cl_eol(linenum);
- else
- oimage[linenum].Line = (LINE *) -1;
- } else if (BufSwrite(linenum))
- do_cl_eol(linenum);
- else
- oimage[linenum].Line = (LINE *) -1;
- } else if (oimage[linenum].Line) { /* Not the same ... make sure */
- i_set(linenum, 0);
- do_cl_eol(linenum);
- }
- }
-
- do_cl_eol(linenum)
- register int linenum;
- {
- cl_eol();
- #ifdef UNIX
- oimage[linenum] = nimage[linenum]; /***/
- #else
- /* oimage[linenum].StartCol = nimage[linenum].StartCol;
- oimage[linenum].Sflags = nimage[linenum].Sflags;
- oimage[linenum].Line = nimage[linenum].Line;
- oimage[linenum].Window = nimage[linenum].Window;
- */
- movmem(nimage+linenum,oimage+linenum,sizeof(struct scrimage));
- #endif
- }
-
-
- int InMode = 0;
-
- CopyTo(to, from, limit)
- register char *to,
- *from,
- *limit;
- {
- while (from <= limit)
- *to++ = *from++;
- }
-
- /* ID character routines full of special cases and other fun stuff like that.
- It actually works thougth ... */
-
- IDchar(new, lineno, col)
- register char *new;
- {
- int i,
- j,
- oldlen,
- NumSaved;
- register SCRLNE *sline = &Screen[lineno];
-
- oldlen = sline->s_length - sline->s_line;
-
- for (i = col; i < oldlen && new[i] != 0; i++)
- if (sline->s_line[i] != new[i])
- break;
- if (new[i] == 0 || i == oldlen)
- return !(new[i] == 0 && i == oldlen);
-
- for (j = i + 1; j < oldlen && new[j]; j++) {
- if (new[j] == sline->s_line[i]) {
- NumSaved = IDcomp(new + j, sline->s_line + i,
- strlen(new)) + NumSimilar(new + i,
- sline->s_line + i, j - i);
- if (OkayInsert(NumSaved, j - i)) {
- InsChar(lineno, i, j - i, new);
- ignore(IDchar(new, lineno, j));
- return 1; /* Difference */
- }
- }
- }
-
- for (j = i + 1; j < oldlen && new[i]; j++) {
- if (new[i] == sline->s_line[j]) {
- NumSaved = IDcomp(new + i, sline->s_line + j,
- oldlen - j);
- if (OkayDelete(NumSaved, j - i, new[oldlen] == 0)) {
- DelChar(lineno, i, j - i);
- ignore(IDchar(new, lineno, j));
- return 1;
- }
- }
- }
- return 1;
- }
-
- NumSimilar(s, t, n)
- register char *s,
- *t;
- {
- register int num = 0;
-
- while (n--)
- if (*s++ == *t++)
- num++;
- return num;
- }
-
- IDcomp(s, t, len)
- register char *s,
- *t;
- {
- register int i;
- int num = 0,
- nonspace = 0;
- char c;
-
- for (i = 0; i < len; i++) {
- if ((c = *s++) != *t++)
- break;
- if (c != ' ')
- nonspace++;
- if (nonspace)
- num++;
- }
-
- return num;
- }
-
- OkayDelete(Saved, num, samelength)
- {
- static int DelIn = 0,
- CElen = 0;
-
- if (DelIn == 0) {
- DelIn = weight(DELETE);
- CElen = weight(CLREOL);
- }
-
- /* If the old and the new are the same length, then we don't
- * have to clear to end of line. We take that into consideration.
- */
- return ((Saved + (!samelength ? CElen : 0)) > (DelIn * num));
- }
-
- OkayInsert(Saved, num)
- {
- int n;
-
- if (hasIM) { /* Good terminal. Fewer characters in this case */
- static int InsIn = 0;
-
- if (InsIn == 0)
- InsIn = weight(INSERT);
-
- if (InMode) /* We are already in insert mode */
- n = num;
- else
- n = num + InsIn;
- } else {
- static int IClen = 0;
-
- if (IClen == 0)
- IClen = weight(INSERTCH);
- n = 2 * num * IClen;
- }
- return Saved > n;
- }
-
-
- DelChar(lineno, col, num)
- {
- register int i;
-
- Placur(lineno, col);
- for (i = 0; i < num; i++)
- del_chr();
- CopyTo(Screen[lineno].s_line + col, Screen[lineno].s_line + col + num,
- Screen[lineno].s_length);
- Screen[lineno].s_length -= num;
- }
-
- InsChar(lineno, col, num, new)
- char *new;
- {
- register char *sp1,
- *sp2, /* To push over the array */
- *sp3; /* Last character to push over */
-
- int WithSpaces = !(hasIM);
- /* If no insert mode then the IC inserts spaces
- * for us, and the screen image has to reflect
- * that.
- */
- int i;
-
- i_set(lineno, 0);
- sp2 = Curline->s_length + num;
- if (sp2 >= cursend) {
- i_set(lineno, CO - (sp2 - cursend) - 1);
- cl_eol();
- sp2 = cursend - 1;
- }
- Curline->s_length = sp2;
- sp1 = sp2 - num;
- sp3 = Curline->s_line + col;
-
- while (sp1 >= sp3)
- *sp2-- = *sp1--;
- sp1 = Curline->s_line + col;
- new += col;
- for (i = 0; i < num; i++)
- *sp1++ = (WithSpaces) ? ' ' : new[i];
- /* The internal screen is correct, and now we have to do
- * the physical stuff
- */
-
- Placur(lineno, col);
- if (!WithSpaces) {
- if (!InMode) {
- ins_mode();
- InMode++;
- }
- #ifdef UNIX
- for (i = 0; i < num; i++) {
- outchar(new[i]);
- CapCol++;
- }
- #else
- writechars(new,new +num -1);
- #endif
- } else {
- ins_mode();
- for (i = 0; i < num; i++) {
- outchar(' ');
- CapCol++;
- }
- ex_ins_mode();
- }
- }
-
-
- /*-----------------------o.s. dependent-------------------------*/
- /* end */